﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Games.Klotski
{
    class Game
    {
        internal const int LENGTH = 6;
        internal List<Piece> Pieces;
        private readonly List<int> lis = new List<int>();
        public void Init(string map)
        {
            var data = map.Split(';');
            MinStep = int.Parse(data[1]);
            Pieces = data[0].Split(',').Select((x, i) => new Piece(x, i)).ToList();
            lis.Clear();
            foreach(var p in Pieces)
            {
                lis.AddRange(PlacesOfPiece(p));
            }
            this.IsFinished = false;
        }
        /// <summary>
        /// 返回指定的方块占据的位置
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        private List<int> PlacesOfPiece(Piece p)
        {
            List<int> lst = new List<int>();
            for(int i = 0; i < p.H; i++)
            {
                for(int j = 0; j < p.W; j++)
                {
                    lst.Add((i + p.Y) * LENGTH + j + p.X);
                }
            }
            return lst;
        }

        public (int, int) GetPieceRange(Piece piece)
        {
            if(piece.IsHorizontal)
            {
                var min = piece.X;
                var max = piece.X;
                for(int i = piece.X - 1; i >= 0; i--)
                {
                    var t = piece.Y * LENGTH + i;
                    if(!lis.Contains(t))
                    {
                        min = i;
                    }
                    else
                    {
                        break;
                    }
                }
                for(int i = piece.X + 1; i <= LENGTH - piece.W; i++)
                {
                    var t = piece.Y * LENGTH + i + piece.W - 1;
                    if(!lis.Contains(t))
                    {
                        max = i;
                    }
                    else
                    {
                        break;
                    }
                }
                if(piece.Id == 0 && max == LENGTH - piece.W)
                {
                    max += 2;
                }
                return (min, max);
            }
            else
            {
                var min = piece.Y;
                var max = piece.Y;
                for(int i = piece.Y - 1; i >= 0; i--)
                {
                    var t = i * LENGTH + piece.X;
                    if(!lis.Contains(t))
                    {
                        min = i;
                    }
                    else
                    {
                        break;
                    }
                }
                for(int i = piece.Y + 1; i <= LENGTH - piece.H; i++)
                {
                    var t = (i + piece.H - 1) * LENGTH + piece.X;
                    if(!lis.Contains(t))
                    {
                        max = i;
                    }
                    else
                    {
                        break;
                    }
                }
                return (min, max);
            }
        }

        public void Move(Piece piece, int x, int y)
        {
            if(IsFinished || (x == 0 && y == 0))
            {
                return;
            }
            if(x == 0)
            {
                var dy = y / Math.Abs(y);
                for(var oy = 0; oy != y && !IsFinished; oy += dy)
                {
                    if(dy > 0)
                    {
                        if(!MoveDown(piece))
                        {
                            break;
                        }
                    }
                    else
                    {
                        if(!MoveUp(piece))
                        {
                            break;
                        }
                    }
                }
            }
            else if(y == 0)
            {
                var dx = x / Math.Abs(x);
                for(var ox = 0; ox != x && !IsFinished; ox += dx)
                {
                    if(dx > 0)
                    {
                        if(!MoveRight(piece))
                        {
                            break;
                        }
                    }
                    else
                    {
                        if(!MoveLeft(piece))
                        {
                            break;
                        }
                    }
                }
            }
        }


        /// <summary>
        /// 方块左移
        /// </summary>
        /// <returns></returns>
        private bool MoveLeft(Piece p)
        {
            int tmp = p.Y * LENGTH + p.X - 1;
            if(p.IsHorizontal && p.X > 0 && !lis.Contains(tmp))
            {
                p.X--;
                lis.Add(tmp);
                lis.Remove(tmp + p.W);
                return true;
            }
            return true;
        }
        /// <summary>
        /// 方块右移
        /// </summary>
        /// <returns></returns>
        private bool MoveRight(Piece p)
        {
            int tmp = p.Y * LENGTH + p.X + p.W;
            if(p.IsHorizontal && !lis.Contains(tmp))
            {
                if(p.X + p.W < LENGTH || p.Id == 0)
                {
                    p.X++;
                    lis.Add(tmp);
                    lis.Remove(tmp - p.W);
                    if(p.Id == 0 && p.X + p.W >= LENGTH)
                    {
                        this.IsFinished = true;
                    }
                    return true;
                }
            }
            return false;
        }
        /// <summary>
        /// 方块上移
        /// </summary>
        /// <returns></returns>
        private bool MoveUp(Piece p)
        {
            int tmp = (p.Y - 1) * LENGTH + p.X;
            if(!p.IsHorizontal && p.Y > 0 && !lis.Contains(tmp))
            {
                p.Y--;
                lis.Add(tmp);
                lis.Remove(tmp + p.H * LENGTH);
                return true;
            }
            return false;
        }
        /// <summary>
        /// 方块下移
        /// </summary>
        /// <returns></returns>
        private bool MoveDown(Piece p)
        {
            int tmp = (p.Y + p.H) * LENGTH + p.X;
            if(!p.IsHorizontal && p.Y + p.H < LENGTH && !lis.Contains(tmp))
            {
                p.Y++;
                lis.Add(tmp);
                lis.Remove(tmp - p.H * LENGTH);
                return true;
            }
            return false;
        }

        public bool IsFinished { get; private set; }
        public int MinStep { get; private set; }
    }
}
